/*
 * @file range.h
 *
 * Some classes for representing ranges
 *
 * @author Dahua Lin
 */

#ifndef _MSC_VER
#pragma once
#endif

#ifndef GMLPP_RANGE_H_
#define GMLPP_RANGE_H_

#include <gmlpp/base/basic_defs.h>

namespace gml
{

	namespace detail
	{

		template<typename TInt, bool IsSigned> struct int_pred_a;

		template<typename TInt>
		struct int_pred_a<TInt, true>
		{
		public:
			GML_ENSURE_INLINE
			static bool is_in(const TInt v, const TInt K) { return v >= 0 && v < K; }
		};

		template<typename TInt>
		struct int_pred_a<TInt, false>
		{
		public:
			GML_ENSURE_INLINE
			static bool is_in(const TInt v, const TInt K) { return v < K; }
		};

		template<typename TInt>
		struct int_pred
		{
		public:
			GML_ENSURE_INLINE
			static bool is_in(const TInt v, const TInt K)  // test 0 <= v < K
			{
				return int_pred_a<TInt, std::numeric_limits<TInt>::is_signed>::is_in(v, K);
			}
		};

	}


	/**
	 * simple integer range: [0, K) = [0, K-1]
	 */
	template<typename TInt>
	class SRange
	{
	public:
		typedef TInt value_type;

	public:
		explicit SRange(TInt K)
		: m_K(K)
		{
		}

		GML_ENSURE_INLINE TInt a() const
		{
			return 0;
		}

		GML_ENSURE_INLINE TInt b() const
		{
			return m_K;
		}

		GML_ENSURE_INLINE TInt size() const
		{
			return m_K;
		}

		GML_ENSURE_INLINE bool contains(TInt v) const
		{
			return detail::int_pred<TInt>::is_in(v, m_K);
		}

		GML_ENSURE_INLINE TInt index(TInt v) const
		{
			return v;
		}

		GML_ENSURE_INLINE TInt operator[] (TInt i) const
		{
			return i;
		}

	private:
		TInt m_K;

	}; // end class SRange


	template<typename TInt>
	GML_ENSURE_INLINE inline SRange<TInt> srange(TInt K)
	{
		return SRange<TInt>(K);
	}


	/**
	 * integer range: [a, b) = [a, b-1]
	 */
	template<typename TInt>
	class Range
	{
	public:
		typedef TInt value_type;

	public:
		explicit Range(TInt a_, TInt b_)
		: m_a(a_), m_b(b_)
		{
		}

		GML_ENSURE_INLINE TInt a() const
		{
			return m_a;
		}

		GML_ENSURE_INLINE TInt b() const
		{
			return m_b;
		}

		GML_ENSURE_INLINE TInt size() const
		{
			return m_b - m_a;
		}

		GML_ENSURE_INLINE bool contains(TInt v) const
		{
			return v >= m_a && v < m_b;
		}

		GML_ENSURE_INLINE TInt index(TInt v) const
		{
			return v - m_a;
		}

		GML_ENSURE_INLINE TInt operator[] (TInt i) const
		{
			return m_a + i;
		}

	private:
		TInt m_a;
		TInt m_b;

	}; // end class Range

	template<typename TInt>
	GML_ENSURE_INLINE inline Range<TInt> range(TInt a, TInt b)
	{
		return Range<TInt>(a, b);
	}


}

#endif
